package com.mmd.base.utils;

import cn.hutool.core.date.DateUtil;
import com.mmd.core.utils.CommonUtils;
import com.mmd.core.utils.FunctionUtils;
import lombok.SneakyThrows;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

public class DateUtils {

    private static final DateTimeFormatter yyyyMMddHHmmss = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter YYYYMMddHHmmss = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    private static final DateTimeFormatter yyyyMMdd = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    public static final String YYYY_MM_DD = "yyyy-MM-dd";
    private static final DateTimeFormatter yyyy = DateTimeFormatter.ofPattern("yyyy");

    private static final long ONE_MILLISECOND = 1000L;
    private static final long ONE_MINUTE = 60000L;
    private static final long ONE_HOUR = 3600000L;
    private static final long ONE_DAY = 86400000L;

    private static final String ONE_SECOND_AGO = "秒前";
    private static final String ONE_MINUTE_AGO = "分钟前";
    private static final String ONE_HOUR_AGO = "小时前";
    private static final String ONE_DAY_AGO = "天前";
    private static final String ONE_MONTH_AGO = "1个月前";
    private static final String TWO_MONTH_AGO = "2个月前";
    private static final String THREE_MONTH_AGO = "3个月前";
    private static final String FOUR_MONTH_AGO = "4个月前";
    private static final String FIVE_MONTH_AGO = "5个月前";
    private static final String SIX_MONTH_AGO = "6个月前";
    private static final String SEVEN_MONTH_AGO = "7个月前";
    private static final String EIGHT_MONTH_AGO = "8个月前";
    private static final String NINE_MONTH_AGO = "9个月前";
    private static final String TEN_MONTH_AGO = "10个月前";
    private static final String ELEVEN_MONTH_AGO = "11个月前";
    private static final String ONE_YEAR_AGO = "1年前";

    /**
     * 获取年龄
     */
    public static Integer getAge(String birthday) {
        if (StringUtils.hasText(birthday)) {
            try {
                return DateUtil.age(Optional.ofNullable(DateUtils.getDateOfFormat(birthday, "yyyy-MM-dd")).orElse(DateUtil.date()), DateUtil.date());
            } catch (ParseException e) {
                return 18;
            }
        }
        return 18;
    }

    public static List<String> convertToWeekday(List<String> dateList) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String[] weekDays = {"周一", "周二", "周三", "周四", "周五", "周六", "周日"};

        return dateList.stream()
                .map(dateStr -> {
                    LocalDate date = LocalDate.parse(dateStr, formatter);
                    DayOfWeek dayOfWeek = date.getDayOfWeek();
                    return weekDays[dayOfWeek.getValue() - 1];
                })
                .collect(Collectors.toList());
    }

    public static void main(String[] args) {
        BigDecimal ampRatio = getAmpRatio(BigDecimal.valueOf(50), BigDecimal.valueOf(60));
        System.out.println(ampRatio);
    }

    /**
     * 获取较昨日 上周 上月的比例
     */
    public static BigDecimal getAmpRatio(BigDecimal startMoney, BigDecimal endMoney) {
        if (startMoney.compareTo(BigDecimal.ZERO) < 1) return BigDecimal.ZERO;
        if (endMoney.compareTo(BigDecimal.ZERO) < 1) return BigDecimal.ZERO;
        BigDecimal divide = startMoney.divide(endMoney, 3, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(100));
        if (divide.doubleValue() > 1) {
            return divide.subtract(BigDecimal.valueOf(1));
        }
        return BigDecimal.valueOf(1).subtract(divide);
    }


    /**
     * 多久之前
     */
    public static String format(Date date) {
        if (CommonUtils.isNull(date)) return "";
        Calendar calendar = Calendar.getInstance();
        long now = calendar.getTimeInMillis();
        long delta = now - date.getTime();

        // 逻辑判断
        if (delta < ONE_MINUTE) return delta / ONE_MILLISECOND + ONE_SECOND_AGO;
        if (delta < ONE_HOUR) return delta / ONE_MINUTE + ONE_MINUTE_AGO;
        if (delta < ONE_DAY) return delta / ONE_HOUR + ONE_HOUR_AGO;
        if (delta < getTime(calendar, now)) return delta / ONE_DAY + ONE_DAY_AGO;
        if (delta < getTime(calendar, now)) return ONE_MONTH_AGO;
        if (delta < getTime(calendar, now)) return TWO_MONTH_AGO;
        if (delta < getTime(calendar, now)) return THREE_MONTH_AGO;
        if (delta < getTime(calendar, now)) return FOUR_MONTH_AGO;
        if (delta < getTime(calendar, now)) return FIVE_MONTH_AGO;
        if (delta < getTime(calendar, now)) return SIX_MONTH_AGO;
        if (delta < getTime(calendar, now)) return SEVEN_MONTH_AGO;
        if (delta < getTime(calendar, now)) return EIGHT_MONTH_AGO;
        if (delta < getTime(calendar, now)) return NINE_MONTH_AGO;
        if (delta < getTime(calendar, now)) return TEN_MONTH_AGO;
        if (delta < getTime(calendar, now)) return ELEVEN_MONTH_AGO;
        return ONE_YEAR_AGO;
    }


    public static String formatDate(Date date) {
        if (date == null) {
            return "";
        }

        Calendar now = Calendar.getInstance();
        Calendar input = Calendar.getInstance();
        input.setTime(date);

        // 设置周一作为一周的第一天
        now.setFirstDayOfWeek(Calendar.MONDAY);
        input.setFirstDayOfWeek(Calendar.MONDAY);

        // 判断是否是同一天
        if (isSameDay(now, input)) {
            return new SimpleDateFormat("HH:mm").format(date);
        }

        // 判断是否是昨天
        now.add(Calendar.DAY_OF_YEAR, -1);
        if (isSameDay(now, input)) {
            return "昨天 " + new SimpleDateFormat("HH:mm").format(date);
        }

        now.add(Calendar.DAY_OF_YEAR, +1); // 还原

        // 判断是否是同一周
        if (isSameWeek(now, input)) {
            // 获取星期几
            String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
            int dayOfWeek = input.get(Calendar.DAY_OF_WEEK);
            return weekDays[dayOfWeek - 1];
        }

        // 判断是否是同一年
        if (now.get(Calendar.YEAR) == input.get(Calendar.YEAR)) {
            return new SimpleDateFormat("MM-dd").format(date);
        }

        // 超过一年
        return new SimpleDateFormat("yyyy-MM-dd").format(date);
    }

    private static boolean isSameDay(Calendar cal1, Calendar cal2) {
        return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)
                && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR);
    }

    private static boolean isSameWeek(Calendar now, Calendar input) {
        return now.get(Calendar.YEAR) == input.get(Calendar.YEAR)
                && now.get(Calendar.WEEK_OF_YEAR) == input.get(Calendar.WEEK_OF_YEAR);
    }



    /**
     * 剩余多少分钟
     */
    public static Integer residueMina(Date date) {
        Calendar calendar = Calendar.getInstance();
        long now = calendar.getTimeInMillis();
        long delta = now - date.getTime();

        // 逻辑判断
        if (delta < ONE_MINUTE) return Math.toIntExact(delta / ONE_MILLISECOND);
        if (delta < ONE_HOUR) return Math.toIntExact(delta / ONE_MINUTE);
        return 0;
    }

    /**
     * 多久之前
     */
    public static String formatToDateTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        long now = calendar.getTimeInMillis();
        long delta = now - date.getTime();
        // 逻辑判断
        if (delta < ONE_MINUTE) return delta / ONE_MILLISECOND + ONE_SECOND_AGO;
        if (delta < ONE_HOUR) return delta / ONE_MINUTE + ONE_MINUTE_AGO;
        if (delta < ONE_DAY) return delta / ONE_HOUR + ONE_HOUR_AGO;
        if (delta < getTime(calendar, now)) {
            return DateUtils.format(date, "MM-dd");
        }
        return DateUtils.format(date, "yyyy-MM-dd");
    }

    private static long getTime(Calendar calendar, long now) {
        calendar.add(Calendar.MONTH, -1);
        return now - calendar.getTimeInMillis();
    }

    /**
     * 指定日期增加指定类型时间
     *
     * @param date     指定日期
     * @param time     时间
     * @param calendar {@link Calendar#DATE ...}
     */
    public static Date assignDateAddTime(Date date, Integer time, Integer calendar) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        instance.add(calendar, time);
        return instance.getTime();
    }

    /**
     * 获取置顶日期格式化
     *
     * @param date   日期
     * @param patter yyyy-MM-dd HH:mm:ss
     */
    public static String format(Date date, String patter) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(patter);
        return simpleDateFormat.format(date);
    }

    /**
     * 获取两个指定格式的日期相差天数
     * @param start 0000-00-00
     * @param end 0000-00-00
     * @param patter yyyy yyyy-MM-dd MM-dd
     * @return date
     */
    /**
     * 获取两个指定格式的日期相差天数
     *
     * @param start 0000-00-00
     * @param end   0000-00-00
     * @return date
     */
    public static Integer startEndDay(Date start, Date end) {
        long l = start.getTime() - end.getTime();
        return (int) (Math.abs(l) / (24 * 60 * 60 * 1000));
    }

    /**
     * 获取两个指定格式的日期相差天数
     *
     * @param date         0000-00-00
     * @param day          N
     * @param patter       yyyy yyyy-MM-dd MM-dd
     * @param resultPatter yyyy yyyy-MM-dd MM-dd
     * @return date
     */
    public static String ofDateSubDay(String date, Integer day, String patter, String resultPatter) throws ParseException {
        SimpleDateFormat result = new SimpleDateFormat(resultPatter);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(patter);
        Date dates = simpleDateFormat.parse(date);
        Calendar instance = Calendar.getInstance();
        instance.setTime(dates);
        instance.add(Calendar.DATE, -day);
        Date time = instance.getTime();
        return result.format(time);
    }

    /**
     * 获取指定格式日期
     */
    public static String getYYYY(Integer year) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(new Date());
        instance.add(Calendar.YEAR, year);
        return DateUtils.format(instance.getTime(), "yyyy");
    }

    /**
     * 获取指定格式日期
     */
    public static String getYYYYMM() {
        Calendar instance = Calendar.getInstance();
        instance.setTime(new Date());
        return DateUtils.format(instance.getTime(), "yyyy-MM");
    }


    /**
     * 获取指定格式日期
     */
    public static String getYYYYMMDD() {
        return yyyyMMdd.format(LocalDateTime.now());
    }

    /**
     * 获取指定格式日期
     */
    public static String getYYYYMMDDHHmmss() {
        return yyyyMMddHHmmss.format(LocalDateTime.now());
    }

    /**
     * 获取指定格式日期
     */
    public static String getYYYYMMDDHHmmssNo() {
        return YYYYMMddHHmmss.format(LocalDateTime.now());
    }

    /**
     * 获取指定格式日期
     *
     * @param patter yyyy-MM-dd
     */
    public static String getDate(String patter) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(patter);
        return dateTimeFormatter.format(LocalDateTime.now());
    }

    /**
     * 将标准时间格式 yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z' 转为国内标准时间格式 yyyy-MM-dd HH:mm:ss
     *
     * @param timeStr yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String interceptTime(String timeStr) {
        if (!StringUtils.isEmpty(timeStr)) {
            if (timeStr.contains("T")) {
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'", Locale.ENGLISH);
                LocalDateTime ldt = LocalDateTime.parse(timeStr, df);
                ZoneId currentZone = ZoneId.of("UTC");
                ZoneId newZone = ZoneId.of("Asia/Shanghai");
                timeStr = ldt.atZone(currentZone).withZoneSameInstant(newZone).toLocalDateTime().toString();
            }
        }
        LocalDateTime parse = LocalDateTime.parse(timeStr);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return dateTimeFormatter.format(parse);
    }

    /**
     * 获取当前Date
     */
    public static Date currentDate() {
        return new Date();
    }

    /**
     * 指定格式日期转为Date
     */
    public static Date getDateOfFormat(String date, String patter) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(patter);
        return simpleDateFormat.parse(date);
    }

    /**
     * 获取今日开始时间
     */
    public static String getDayBegin() {
        return getDayBegin(new Date());
    }

    /**
     * 获取昨日开始时间
     */
    public static String getYestDayBegin() {
        Calendar instance = Calendar.getInstance();
        instance.setTime(new Date());
        instance.add(Calendar.DATE, -1);
        return getDayBegin(instance.getTime());
    }


    /**
     * 获取昨日结束时间
     */
    public static String getYestDayEnd() {
        Calendar instance = Calendar.getInstance();
        instance.setTime(new Date());
        instance.add(Calendar.DATE, -1);
        return getDayEnd(instance.getTime());
    }


    /**
     * 获取指定日期开始时间
     *
     * @param date 日期
     */
    public static String getDayBegin(Date date) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        instance.set(Calendar.HOUR_OF_DAY, 0);
        instance.set(Calendar.MINUTE, 0);
        instance.set(Calendar.SECOND, 0);
        return FunctionUtils.map(instance.getTime(), "yyyy-MM-dd HH:mm:ss", DateUtils::format);
    }

    /**
     * 获取今日结束时间
     */
    public static String getDayEnd() {
        return getDayEnd(new Date());
    }


    /**
     * 获取指定日期结束时间
     *
     * @param date 日期
     */
    public static String getDayEnd(Date date) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        instance.set(Calendar.HOUR_OF_DAY, 23);
        instance.set(Calendar.MINUTE, 59);
        instance.set(Calendar.SECOND, 59);
        return FunctionUtils.map(instance.getTime(), "yyyy-MM-dd HH:mm:ss", DateUtils::format);
    }

    /**
     * 获取本月的开始时间与结束时间
     */
    public static Map<String, String> getMonthTime() throws ParseException {
        Calendar a = Calendar.getInstance();
        a.set(Calendar.DATE, 1);//把日期设置为当月第一天
        a.roll(Calendar.DATE, -1);//日期回滚一天，也就是最后一天
        int maxDate = a.get(Calendar.DATE);
        SimpleDateFormat sdfTwo = new SimpleDateFormat("yyyy-MM-");
        String startTime = sdfTwo.format(new Date()) + "01 00:00:00";
        String endTime = sdfTwo.format(new Date()) + maxDate + " 23:59:59";
        Map<String, String> map = new HashMap<>();
        map.put("startTime", startTime);
        map.put("endTime", endTime);
        return map;
    }

    /**
     * 获取上月的开始时间与结束时间
     */
    public static Map<String, String> getYestMonthTime(int month) throws ParseException {
        LocalDate now = LocalDate.now();
        LocalDate localDate = now.minusMonths(month);
        LocalDate localDate1 = localDate.withDayOfMonth(1);
        LocalDate localDate2 = localDate.withDayOfMonth(localDate.lengthOfMonth());
        System.out.println(localDate1 + " ");
        System.out.println(localDate2);
        Map<String, String> map = new HashMap<>();
        map.put("startTime", localDate1 + " 00:00:00");
        map.put("endTime", localDate2 + " 23:59:59");
        System.out.println(map.toString());
        return map;
    }


    /**
     * @param deltaWeeks 相对于当前位置的前几周或者后几周
     */
    public static Map<String, String> getWeekBeginDateAndEndDate(int deltaWeeks) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DAY_OF_YEAR, deltaWeeks * 7);
        int currentDay = calendar.get(Calendar.DAY_OF_WEEK);
        if (currentDay == 1) {
            currentDay = 7;
        } else {
            currentDay = currentDay - 1;
        }
        calendar.add(Calendar.DAY_OF_YEAR, 1 - currentDay);
        Date date = calendar.getTime();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_YEAR, 6);
        Map<String, String> map = new HashMap<>();
        map.put("startTime", format.format(date) + " 00:00:00");
        map.put("endTime", format.format(calendar.getTime()) + " 23:59:59");
        return map;
    }

    //获取今天 本周 本月 本年
    @SneakyThrows
    public static Map<String, String> getTimeByType(Integer type) {
        if (type == 0) {
            Map<String, String> map = new HashMap<>();
            map.put("startTime", getDayBegin());
            map.put("endTime", getDayEnd());
            return map;
        } else if (type == 1) {
            return getStartOrEndDayOfWeek();
        } else if (type == 2) {
            return getMonthTime();
        } else {
            LocalDate startOfYear = LocalDate.now().withDayOfYear(1);
            Map<String, String> map = new HashMap<>();
            map.put("startTime",  startOfYear.format(yyyyMMdd) + " 00:00:00");
            map.put("endTime", getDayEnd());
            return map;
        }
    }


    /**
     * 根据类型返回日期列表
     * @param type 0=日（最近7天），1=周（最近7周的周一），2=月（最近7月的第一天），3=年（最近7年1月1日）
     * @return 日期列表（格式为 yyyy-MM-dd）
     */
    public static List<String> getLastDatesByType(int type) {
        List<String> result = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate today = LocalDate.now();

        switch (type) {
            case 0: // 最近24 小时
                LocalDateTime now = LocalDateTime.now();
                formatter = DateTimeFormatter.ofPattern("HH:mm");
                for (int i = 0; i < 7; i++) {
                    result.add(now.minusHours(i * 3).format(formatter));
                }
                break;
            case 1: // 最近7天
                for (int i = 6; i >= 0; i--) {
                    result.add(today.minusDays(i).format(formatter));
                }
                break;

            case 2: // 按月
                LocalDate firstOfMonth = today.withDayOfMonth(1);
                formatter = DateTimeFormatter.ofPattern("MM-dd");
                for (int i = 6; i >= 0; i--) {
                    result.add(firstOfMonth.minusMonths(i).format(formatter));
                }
                break;

            case 3: // 最近七年
                LocalDate firstOfYear = today.withDayOfYear(1);
                formatter = DateTimeFormatter.ofPattern("yyyy");
                for (int i = 6; i >= 0; i--) {
                    result.add(firstOfYear.minusYears(i).format(formatter));
                }
                break;

            case 4: // 最近7年（每年1月1日）
//                LocalDate firstOfYear = today.withDayOfYear(1);
//                for (int i = 6; i >= 0; i--) {
//                    result.add(firstOfYear.minusYears(i).format(formatter));
//                }
                break;

            default:
                throw new IllegalArgumentException("不支持的类型: " + type);
        }

        return result;
    }

    //获取昨天 上周 上月 去年
    @SneakyThrows
    public static Map<String, String> getYestTimeByType(Integer type) {
        if (type == 0) {
            Map<String, String> map = new HashMap<>();
            map.put("startTime", getYestDayBegin());
            map.put("endTime", getYestDayEnd());
            return map;
        } else if (type == 1) {
            return getWeekBeginDateAndEndDate(-1);
        } else if (type == 2) {
            return getYestMonthTime(-1);
        } else {
            Map<String, String> map = new HashMap<>();
            map.put("startTime", "");
            map.put("endTime", getDayEnd());
            return map;
        }
    }


        public static Map<String, String> getStartOrEndDayOfWeek() {
            Map<String, String> map = new HashMap<>();
            Date time;
            Calendar cal1 = Calendar.getInstance();
            cal1.add(Calendar.WEEK_OF_MONTH, 0);
            cal1.set(Calendar.DAY_OF_WEEK, 2);
            time = cal1.getTime();
            String dateTime1 = new SimpleDateFormat("yyyy-MM-dd").format(time) + " 00:00:00";

            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.DAY_OF_WEEK, calendar.getActualMaximum(Calendar.DAY_OF_WEEK));
            calendar.add(Calendar.DAY_OF_WEEK, 1);
            time = calendar.getTime();
            String dateTime2 = new SimpleDateFormat("yyyy-MM-dd").format(time) + " 23:59:59";

            map.put("startTime", dateTime1);
            map.put("endTime", dateTime2);
            return map;
        }
}
